import { Injectable } from '@nestjs/common';
import PageDto from './dto/page.dto';
import { User } from '@app/db/entity/User';
import { DbService } from '../../db/db.service';
import { ConfigureService } from '@app/configure';
import { CacheService } from '@app/cache';
import { DataSource, FindOptionsWhere, Like } from 'typeorm';
import * as dayjs from 'dayjs';
import WorkException from 'exception/work.exception';
import { maskPhoneNumber } from 'utils';
import { ImclientService } from '@app/imclient';

@Injectable()
export class UserService {
    constructor(
        private readonly db:DbService,
        private readonly config:ConfigureService,
        private readonly cache:CacheService,
        private readonly dataSource: DataSource,
        private readonly imclient:ImclientService,
    ){}


    async page(dto:PageDto) {
        let result:PaginationResult<User> = {
            total : 0,
            rows : []
        }

        let where:FindOptionsWhere<User> = {
            
        }


        if(dto.name) {
            where.name = Like('%' + dto.name + '%')
        }

        if(dto.phone) {
            where.phone = dto.phone
        }

        if(dto.imUserId) {
            where.imUserId = dto.imUserId
        }

        result.total = await this.db.user.count(where)

        if(result.total > 0) {
            result.rows = await this.db.user.pagination(dto.pageNo, dto.pageSize, where, null, {id : 'DESC'})
        }

        return result
    }

    async add(dto:User) {
        const imUserId = dto.imUserId
        const info = {
            avatar: this.config.get('upload.staticURL') + dto.avatar,
            name: dto.name,
        }

        let r = await this.db.user.findOne({phone: dto.phone}, {id:true})
        if(r != null) throw new WorkException('手机号码已存在')
        r = await this.db.user.findOne({imUserId: dto.imUserId}, {id:true})
        if(r != null) throw new WorkException('ID已存在')

        const queryRunner = this.dataSource.createQueryRunner();

        await queryRunner.connect();
        await queryRunner.startTransaction();
        try {
            const r = await queryRunner.manager.insert(User, {...dto, official: true, atIm: 1, registerTime: dayjs().unix()})
        
            const r2 = await this.imclient.createUser(imUserId, info)

            

            if(r2 == null || r2.code != 200) {console.log(r2)
                await queryRunner.rollbackTransaction();
                return false
            }

            await queryRunner.commitTransaction();

            return true
        } catch (err) {
            console.log(err)
            await queryRunner.rollbackTransaction();
        } finally { 
            await queryRunner.release();
        }

        return false
    }

    async update(dto:User) {
        const id = dto.id
        const row = await this.db.user.findOne({id : id})
        if(!row) return false

        const updateData:KeyToValueType<User> = {}

        for(let k in row) {
            if(k in dto) {
                if(dto[k] != row[k]) {
                    updateData[k] = dto[k]
                }
            }
        }


        if(Object.keys(updateData).length > 0) {

            if(updateData.name == undefined && updateData.avatar == undefined) {
                return this.db.user.update({id: dto.id}, updateData)
            }



            const queryRunner = this.dataSource.createQueryRunner();

            await queryRunner.connect();
            await queryRunner.startTransaction();

            try {
                await queryRunner.manager.update(User, {id: id}, updateData)

                let data:any = {}
                if(updateData.name) {
                    data.name = updateData.name
                }
                if(updateData.avatar) {
                    data.avatar = this.config.get('upload.staticURL') + updateData.avatar
                }
                
                const r2 = await this.imclient.update(row.imUserId, data)

                if(r2 == null || r2.code != 200) {
                    await queryRunner.rollbackTransaction();
                    return false
                }


                await queryRunner.commitTransaction();
                return true

            } catch (err) {
                await queryRunner.rollbackTransaction();
            } finally { 
                await queryRunner.release();
            }

            return false
        }


        return true

    }


    async del(id:number) {
        let row = await this.db.user.findOne({ id }, {id: true, imUserId:true, atIm: true})
        if(!row) return

        return this.db.user.delete({id : id})
    }
    
}
